#ifndef MOCHA_DETAIL_GAME_HPP_INCLUDED
#define MOCHA_DETAIL_GAME_HPP_INCLUDED

/**
 * @file
 */

#include <cstdint>
#include <boost/signal.hpp>
//#include <boost/signals/trackable.hpp>
#include "mocha/plugin_factory.hpp"
#include "mocha/pointers.hpp"

namespace mocha {
/**
 * Base of game objects, which act as the primary interface to the core.
 * All Mocha based programs should derive from this base and implement its detailed functionality.
 */
class game {
public:
	/// Signal fired when the game is started.
	boost::signal<void(const game* const)> started;
	/// Signal fired when the game is stopped.
	boost::signal<void(const game* const)> stopped;
	virtual ~game();
	/**
	 *
	 */
	void start();
	/**
	 *
	 */
	void stop();
	/**
	 * @return The event queue.
	 */
	event_queue_ptr_t event_queue();
	/**
	 * @return The event queue.
	 */
	const_event_queue_ptr_t event_queue() const;
	/**
	 * @return The graphics device.
	 */
	mocha::graphics::graphics_ptr_t graphics();
	/**
	 * @return The graphics device.
	 */
	mocha::graphics::const_graphics_ptr_t graphics() const;
protected:
	game();
	/**
	 * Panics, immediately terminating the program after some logging.
	 * This function is somewhat platform dependent, and the cleanliness of the shutdown may differ.
	 * Plugins are purged before terminating.
	 * This function should only be called if a fatal error is detected and the program should end.
	 */
	void panic();
	/**
	 * Searches for events in the event queue and fires relevant signals from all subsystems.
	 * No events are removed from the queue.
	 */
	void peek_all_event_signals();
	/**
	 * Searches for events from the event queue and fires relevant signals from all subsystems.
	 * All relevant events are popped from the queue.
	 */
	void pop_all_event_signals();
	/**
	 * Called when the game is started. If overridden, this function should perform initialization.
	 * @return True if initialization was successful. If false is returned, the game is aborted, as this indicates that initialization failed.
	 * @see do_stop
	 */
	virtual bool do_start();
	/**
	 * Called when the game is stopped. If overriden, this function should perform deinitialization.
	 * @return True if deinitialization was successful. If false is returned, the program is aborted immediately (this obviously means the game cannot be started again, and is very different from a clean stop).
	 * @see do_start
	 */
	virtual bool do_stop();
	/**
	 * Called each time the game should update game logic, etc..
	 * This member function must be overridden by subclasses and is called periodically (by default, 30 times per second).
	 * @param elapsed Elapsed ticks since the last update.
	 * @param factor Time factor at the time of the call. The time factor is the ratio of desired update interval to actual update interval. When multiplied with time sensitive operations (such as movement), it helps control the rate of updating.
	 * @see do_paint
	 */
	virtual void do_update(std::uint64_t elapsed, float factor) = 0;
	/**
	 * Called each time the game should be (re)painted.
	 * This member function must be overridden by subclasses.
	 * @see do_update
	 */
	virtual void do_paint() = 0;
private:
	void init();
	void deinit();
	void loop();
	void update();
	void paint();
	plugin_factory_ptr_t plugin_factory_;
	event_queue_ptr_t event_queue_;
	mocha::graphics::graphics_ptr_t graphics_;
	int loop_flag_;
};
}

#endif

